package com.webguard.outlierdetection.service.impl;

import com.alibaba.dashscope.app.Application;
import com.alibaba.dashscope.app.ApplicationParam;
import com.alibaba.dashscope.exception.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webguard.outlierdetection.pojo.AnomalyRecord;
import com.webguard.outlierdetection.pojo.Result;
import com.webguard.outlierdetection.service.LLMService;
import com.webguard.outlierdetection.service.NetworkAnomalyService;
import jakarta.annotation.PostConstruct;
import org.apache.hc.core5.http.HttpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.*;

@Service
public class LLMServiceImpl implements LLMService {
    private static final Logger logger = LoggerFactory.getLogger(LLMServiceImpl.class);
    private static final ObjectMapper mapper = new ObjectMapper();

    private final BlockingQueue<String> dataQueue = new LinkedBlockingQueue<>(5000);
    private final Executor processingExecutor;
    private final NetworkAnomalyService networkAnomalyService;
    private final ScheduledExecutorService monitorExecutor = Executors.newSingleThreadScheduledExecutor();

    @Value("${llm.api.key}") private String apiKey;
    @Value("${llm.api.appId}") private String appId;

    public LLMServiceImpl(
            @Qualifier("processingExecutor") Executor processingExecutor,
            NetworkAnomalyService networkAnomalyService) {
        this.processingExecutor = processingExecutor;
        this.networkAnomalyService = networkAnomalyService;
    }

    @PostConstruct
    public void init() {
        startProcessingWorkers();
        startQueueMonitoring();
    }

    private void startProcessingWorkers() {
        for (int i = 0; i < 10; i++) {
            processingExecutor.execute(this::processQueue);
        }
    }

    private void startQueueMonitoring() {
        monitorExecutor.scheduleAtFixedRate(() -> {
            logger.info("Queue Status: Size={}/{} ({}%)",
                    dataQueue.size(),
                    dataQueue.remainingCapacity(),
                    (dataQueue.size() * 100) / (dataQueue.size() + dataQueue.remainingCapacity())
            );
        }, 5, 5, TimeUnit.SECONDS);
    }

    @Override
    public void submitRawData(String rawData) {
        if (!dataQueue.offer(rawData)) {
            logger.warn("Queue overload! Rejected data: {}", rawData);
            throw new RejectedExecutionException("系统繁忙，请稍后重试");
        }
        logger.debug("Data enqueued: {}", rawData);
    }

    private void processQueue() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                String rawData = dataQueue.poll(1, TimeUnit.SECONDS);
                if (rawData != null) {
                    processSingleData(rawData);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    @Async("processingExecutor")
    public void processSingleData(String rawData) {
        try {
            ApplicationParam param = ApplicationParam.builder()
                    .apiKey(apiKey)
                    .appId(appId)
                    .prompt(buildPrompt(rawData))
                    .build();

            String resultText = new Application()
                    .call(param)
                    .getOutput().getText();

            AnomalyRecord record = parseResponse(resultText);
            logger.info("API Response parsed: {}", record);
            networkAnomalyService.saveAnomalyRecordAsync(record);
            logger.debug("Passed to save service: {}", record.getDestinationPort());
            logger.info("Processed data: {}", rawData);

        } catch (JsonProcessingException e) {
            logger.error("Invalid response format: {}", rawData);
        } catch (Exception e) {
            logger.error("Processing failed: {}", rawData, e);
        }
    }

    private String buildPrompt(String rawData) {
        return String.format(
                "作为网络安全专家，判断标准必须参考知识库中的各种流量特征，请简要快速分析用户所给的原始流量数据并最后返回标准化的JSON。请严格按以下格式返回JSON分析结果：\n" +
                        "输入数据：%s\n" +
                        "要求输出结构：{\n" +
                        "  \"destination_port\": 数值端口,\n" +
                        "  \"flow_duration\": \"时长（单位秒）\",\n" +
                        "  \"flow_bytes_per_s\": \"字节/秒\",\n" +
                        "  \"flow_packets_per_s\": \"包数/秒\",\n" +
                        "  \"syn_flag_count\": SYN标记数,\n" +
                        "  \"rst_flag_count\": RST标记数,\n" +
                        "  \"ack_flag_count\": ACK标记数,\n" +
                        "  \"type\": \"攻击类型=（BENIGN/DDos/PortScan/ISCX/WebAttacks/Infilteration）\"\n" +
                        "}",
                rawData
        );
    }

    private AnomalyRecord parseResponse(String responseText) throws JsonProcessingException {
        String cleaned = responseText.replaceAll("```json|```", "").trim();
        AnomalyRecord record = mapper.readValue(cleaned, AnomalyRecord.class);
        validateRecord(record);
        return record;
    }

    private void validateRecord(AnomalyRecord record) {
        if (record.getDestinationPort() == null) {
            throw new IllegalArgumentException("缺失必要字段: destination_port");
        }
    }

    @Override
    public int queueRemainingCapacity() {
        return dataQueue.remainingCapacity();
    }

    @Override
    public Result<String> analyzeRawData(String rawData) {
        try {
            ApplicationParam param = ApplicationParam.builder()
                    .apiKey(apiKey)
                    .appId(appId)
                    .prompt(buildAnalysisPrompt(rawData))
                    .build();
            String responseText = new Application()
                    .call(param)
                    .getOutput().getText();
            return Result.success(parseAnalysisResponse(responseText));
        } catch (ApiException e) {
            logger.error("业务异常: {}");
            return Result.error("分析失败: " + e.getMessage());
        } catch (Exception e) {
            logger.error("未知异常: {}", e.getMessage());
            return Result.error("系统内部错误");
        }
    }
    private String buildAnalysisPrompt(String rawData) {
        return String.format(
                "作为网络安全专家，请严格按以下模板分析原始数据，只返回纯文本内容（不要用任何JSON或代码块）：\n" +
                        "输入数据：%s\n\n" +
                        "输出模板：\n" +
                        "1．基本信息\n" +
                        "｀自标端口(Destination Port)：[端口号]\n" +
                        "· 发生时间(Timestamp)：[时间]\n" +
                        "·异常类型(AnomalyType):[类型]\n" +
                        "·流持续时间(FlowDuration)_：[时长] ms\n" +
                        "· 流量速率(Flow Bytes/s)：[数值] MB/s\n" +
                        "－ 数据包速率 (Flow Packets/s)：[数值] p/s\n\n" +
                        "2.统计数据\n" +
                        "· SYN标志次数(SYN Flag Count)：[次数]\n" +
                        "·RST标志次数(RST FIag Count)： [次数]\n" +
                        "· ACK 标志次数 (ACK Flag Count):[次数]\n\n" +
                        "3.详细流量特征\n" +
                        "· 最大包长度(Max Packet Length》：[长度] bytes\n" +
                        "· 最小包长度(Min Packet Length): [长度] bytes)\n" +
                        "· 平均包长度(Packet Length Mean): [长度] bytes\n" +
                        "· 流IAT均值(Flow IAT Mean):[时间] mS\n" +
                        "· 流IAT最大值(Flow IAT Max)：[时间] mS\n\n" +
                        "4. 可能原因 & 影响\n" +
                        "ㆍ可能原因：[原因描述]\n" +
                        "：影响：[影响描述]\n\n" +
                        "5. 关联IP 信息 （可选)\n" +
                        "· 源IP (Source IP):[IP地址]\n" +
                        "· 且标IP (DestinationIP): [IP地址]\n" +
                        "· 国家/地区(Geo Location):[地区]\n\n" +
                        "6．处理建议\n" +
                        "· 建议1：[具体建议]\n" +
                        "ㆍ建议2：[具体建议]\n" +
                        "－建议3：[具体建议]",
                rawData
        );
    }

    private String parseAnalysisResponse(String responseText) {
        // 清理所有特殊符号和代码块
        return responseText.replaceAll("[`{}]|```", "")
                .replaceAll("\\\\", "")
                .trim();
    }

}
